package com.jvtd.gd_location;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.Context;
import android.util.Log;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.jvtd.gd_location.utils.ProcessUtil;

/*
 * Create by Jack Zhang
 */
public class JvtdLocation
{
  private static final String TAG = "JvtdLocation";

  @SuppressLint("StaticFieldLeak")
  private static volatile JvtdLocation instance;
  private Context mContext;
  private JvtdLocationCallBack mLocationCallBack;

  private JvtdLocation(Context context)
  {
    this.mContext = context;
  }

  public static JvtdLocation getInstance(Context context)
  {
    if (instance == null)
      synchronized (JvtdLocation.class)
      {
        if (instance == null)
          instance = new JvtdLocation(context.getApplicationContext());
      }
    return instance;
  }

  /**
   * 声明AMapLocationClient类对象
   */
  private AMapLocationClient mLocationClient = null;
  /**
   * 声明AMapLocationClientOption对象
   */
  private AMapLocationClientOption mLocationOption = null;
  //声明定位回调监听器
  public AMapLocationListener mLocationListener = new AMapLocationListener()
  {
    @Override
    public void onLocationChanged(AMapLocation aMapLocation)
    {
      if (aMapLocation != null)
      {
        if (aMapLocation.getErrorCode() == 0)
        {
          if (mLocationCallBack != null)
            mLocationCallBack.onLocationChanged(aMapLocation);
        } else
        {
          //定位失败时，可通过ErrCode（错误码）信息来确定失败的原因，errInfo是错误信息，详见错误码表。
          Log.e(TAG, "location Error, ErrCode:" + aMapLocation.getErrorCode() + ", errInfo:" + aMapLocation.getErrorInfo());

          if (mLocationCallBack != null)
            mLocationCallBack.locationError(aMapLocation.getErrorCode(), aMapLocation.getErrorInfo());
        }
      } else if (mLocationCallBack != null)
        mLocationCallBack.onCustomError("location Error, 返回对象为null");
    }
  };

  /**
   * 设置key, 应在初始化之前
   *
   * @param key
   * @return
   */
  public JvtdLocation setApiKey(String key)
  {
    AMapLocationClient.setApiKey(key);
    return this;
  }

  /**
   * 初始化定位
   */
  public JvtdLocation init(JvtdLocationCallBack callBack)
  {
    if (ProcessUtil.isMainProcess(mContext))
    {
      // 初始化定位
      mLocationClient = new AMapLocationClient(mContext);
      // 设置定位回调监听
      mLocationClient.setLocationListener(mLocationListener);

      this.mLocationCallBack = callBack;
    } else
      Log.e(TAG, "init() error");
    return this;
  }

  /**
   * 开启参数配置
   */
  public JvtdLocation openLocationOption()
  {
    //初始化AMapLocationClientOption对象
    mLocationOption = new AMapLocationClientOption();
    return this;
  }

  /**
   * 关闭参数配置
   */
  public void closeLocationOption()
  {
    mLocationOption = null;
  }

  /**
   * 判断是否开启参数配置
   */
  public boolean isOpenLocationOption()
  {
    return mLocationOption != null;
  }

  /**
   * 设置定位场景，目前支持三种场景（签到、出行、运动，默认无场景）
   */
  public JvtdLocation setLocationPurpose(JvtdLocationOption.LocationPurpose locationPurpose)
  {
    if (mLocationOption != null)
    {
      if (locationPurpose == JvtdLocationOption.LocationPurpose.SignIn)
        mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.SignIn);
      else if (locationPurpose == JvtdLocationOption.LocationPurpose.Transport)
        mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Transport);
      else if (locationPurpose == JvtdLocationOption.LocationPurpose.Sport)
        mLocationOption.setLocationPurpose(AMapLocationClientOption.AMapLocationPurpose.Sport);
    } else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置定位模式, 目前支持三种模式 (高精度模式、低功耗模式、仅设备模式, 默认高精度定位模式)
   */
  public JvtdLocation setLocationMode(JvtdLocationOption.LocationMode locationMode)
  {
    if (mLocationOption != null)
    {
      if (locationMode == JvtdLocationOption.LocationMode.Hight_Accuracy)
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
      else if (locationMode == JvtdLocationOption.LocationMode.Battery_Saving)
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Battery_Saving);
      else if (locationMode == JvtdLocationOption.LocationMode.Device_Sensors)
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Device_Sensors);
    } else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置是否gps优先，只在高精度模式下有效。默认关闭
   *
   * @param isGpsFirst true->打开 false->关闭
   */
  public JvtdLocation setGpsFirst(boolean isGpsFirst)
  {
    if (mLocationOption != null)
      mLocationOption.setGpsFirst(isGpsFirst);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置单次定位
   * <p>
   * 获取一次定位结果, 该方法默认为false。
   *
   * @param isOnceLocation true->开启单次定位  false->关闭单次定位
   */
  public JvtdLocation setOnceLocation(boolean isOnceLocation)
  {
    if (mLocationOption != null)
      mLocationOption.setOnceLocation(isOnceLocation);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置单次定位, 返回值为最近3s内精度最高的一次定位结果
   * <p>
   * 设置setOnceLocationLatest(boolean b)接口为true，启动定位时SDK会返回最近3s内精度最高的一次定位结果。
   * 如果设置其为true，setOnceLocation(boolean b)接口也会被设置为true，反之不会，默认为false。
   *
   * @param isOnceLocationLatest true->开启单次定位  false->关闭单次定位
   */
  public JvtdLocation setOnceLocationLatest(boolean isOnceLocationLatest)
  {
    if (mLocationOption != null)
      mLocationOption.setOnceLocationLatest(isOnceLocationLatest);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 自定义连续定位
   * <p>
   * 设置定位间隔,单位毫秒,默认为2000ms，最低1000ms
   *
   * @param millis 定位间隔毫秒值
   */
  public JvtdLocation setInterval(int millis)
  {
    if (mLocationOption != null)
    {
      if (millis >= 1000)
        mLocationOption.setInterval(millis);
      else if (mLocationCallBack != null)
        mLocationCallBack.onCustomError("定位间隔时间过短, 请不要低于1000毫秒");
    } else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置定位同时是否需要返回地址描述（默认返回地址信息）
   * <p>
   * 注意：模式为仅设备模式(Device_Sensors)时无效
   *
   * @param needAddress true->需要返回 false->不需要返回
   */
  public JvtdLocation setNeedAddress(boolean needAddress)
  {
    if (mLocationOption != null)
      mLocationOption.setNeedAddress(needAddress);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置是否允许模拟软件Mock位置结果，多为模拟GPS定位结果，默认为true，允许模拟位置
   * <p>
   * 注意：模式为低功耗模式(Battery_Saving)时无效
   *
   * @param mockEnable true->允许 false->不允许
   */
  public JvtdLocation setMockEnable(boolean mockEnable)
  {
    if (mLocationOption != null)
      mLocationOption.setMockEnable(mockEnable);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置网络请求的协议。可选HTTP或者HTTPS。默认为HTTP
   */
  public JvtdLocation setLocationProtocol(JvtdLocationOption.LocationProtocol locationProtocol)
  {
    if (locationProtocol == JvtdLocationOption.LocationProtocol.HTTP)
      AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTP);
    else if (locationProtocol == JvtdLocationOption.LocationProtocol.HTTPS)
      AMapLocationClientOption.setLocationProtocol(AMapLocationClientOption.AMapLocationProtocol.HTTPS);
    return this;
  }

  /**
   * 设置定位请求超时时间，默认为30秒
   * <p>
   * 注意：自 V3.1.0 版本之后setHttpTimeOut(long httpTimeOut)方法不仅会限制低功耗定位、高精度定位两种模式的定位超时时间，同样会作用在仅设备定位时。
   * 如果单次定位发生超时情况，定位随即终止；连续定位状态下当前这一次定位会返回超时，但按照既定周期的定位请求会继续发起。
   *
   * @param millis 定位请求超时时间, 单位是毫秒，默认30000毫秒，建议超时时间不要低于8000毫秒。
   */
  public JvtdLocation setHttpTimeOut(int millis)
  {
    if (mLocationOption != null)
    {
      if (millis >= 8000)
        mLocationOption.setHttpTimeOut(millis);
      else if (mLocationCallBack != null)
        mLocationCallBack.onCustomError("定位请求超时时间过短, 请不要低于8000毫秒");
    } else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置是否开启定位缓存机制(默认开启)
   * <p>
   * 当开启定位缓存功能，在高精度模式和低功耗模式下进行的网络定位结果均会生成本地缓存，不区分单次定位还是连续定位。GPS定位结果不会被缓存。
   *
   * @param locationCacheEnable true->开启 false->关闭
   */
  public JvtdLocation setLocationCacheEnable(boolean locationCacheEnable)
  {
    if (mLocationOption != null)
      mLocationOption.setLocationCacheEnable(locationCacheEnable);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置是否使用传感器。默认是false
   *
   * @param isSensorEnable true->开启 false->关闭
   */
  public JvtdLocation setSensorEnable(boolean isSensorEnable)
  {
    if (mLocationOption != null)
      mLocationOption.setSensorEnable(isSensorEnable);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 是否主动刷新设备wifi模块，获取最新鲜的wifi列表（wifi新鲜程度决定定位精度）。 默认为true
   * <p>
   * 注意：模式为仅设备模式(Device_Sensors)时无效
   * 如果设置为false会同时停止主动刷新，停止以后完全依赖于系统刷新，定位位置可能存在误差
   *
   * @param isWifiScan true->主动刷新 false->不主动刷新
   */
  public JvtdLocation setWifiScan(boolean isWifiScan)
  {
    if (mLocationOption != null)
      mLocationOption.setWifiScan(isWifiScan);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 设置逆地理信息的语言, 默认值为默认语言（根据所在地区选择语言）
   *
   * @param geoLanguage 默认、英文、中文
   */
  public JvtdLocation setGeoLanguage(JvtdLocationOption.GeoLanguage geoLanguage)
  {
    if (mLocationOption != null)
    {
      if (geoLanguage == JvtdLocationOption.GeoLanguage.DEFAULT)
        mLocationOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);
      else if (geoLanguage == JvtdLocationOption.GeoLanguage.EN)
        mLocationOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.EN);
      else if (geoLanguage == JvtdLocationOption.GeoLanguage.ZH)
        mLocationOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.ZH);
    } else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先开启参数配置->openLocationOption()");
    return this;
  }

  /**
   * 开启定位
   */
  public void startLocation()
  {
    if (mLocationClient != null)
    {
      if (mLocationOption != null)
        mLocationClient.setLocationOption(mLocationOption);
      //设置场景模式后最好调用一次stop，再调用start以保证场景模式生效
      mLocationClient.stopLocation();
      mLocationClient.startLocation();
    } else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先初始化定位->init()");
  }

  /**
   * 停止定位
   */
  public void stopLocation()
  {
    if (mLocationClient != null)
      mLocationClient.stopLocation();//停止定位后，本地定位服务并不会被销毁
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先初始化定位->init()");
  }

  /**
   * 销毁定位客户端
   * <p>
   * 注意: 销毁定位客户端之后，若要重新开启定位请重新New一个AMapLocationClient对象。
   */
  public void destoryLocation()
  {
    if (mLocationClient != null)
    {
      mLocationClient.onDestroy();//销毁定位客户端，同时销毁本地定位服务。
      mLocationClient = null;
    }
    if (mLocationCallBack != null)
      mLocationCallBack = null;
    if (mLocationOption != null)
      mLocationOption = null;
  }

  /**
   * 启动后台定位
   * 注: 开启关闭后台定位接口只是提供一个前台服务通知栏并不具备开始、停止定位的功能，开启、停止定位请调用AMapLocationCLient的startLocation()和stopLocation()接口
   *
   * @param notificationId 通知栏ID，建议整个APP使用一个
   * @param notification   通知
   */
  public void enableBackgroundLocation(int notificationId, Notification notification)
  {
    if (mLocationClient != null)
      mLocationClient.enableBackgroundLocation(notificationId, notification);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先初始化定位->init()");
  }

  /**
   * 关闭后台定位
   * 注: 开启关闭后台定位接口只是提供一个前台服务通知栏并不具备开始、停止定位的功能，开启、停止定位请调用AMapLocationCLient的startLocation()和stopLocation()接口
   *
   * @param isDisenabled true->移除通知栏 false->不会移除通知栏，但是可以手动移除
   */
  public void disableBackgroundLocation(boolean isDisenabled)
  {
    if (mLocationClient != null)
      mLocationClient.disableBackgroundLocation(isDisenabled);
    else if (mLocationCallBack != null)
      mLocationCallBack.onCustomError("请先初始化定位->init()");
  }
}
